package org.sag.faultlocalization;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.sag.coverage.PolicySpreadSheetTestRecord;
import org.sag.coverage.PolicySpreadSheetTestSuite;
import org.sag.mutation.PolicyMutant;
import org.sag.mutation.PolicySpreadSheetMutantSuite;


public class FaultLocalizationExperiment {
	
	private ArrayList<PolicyMutant> policyMutants; 
	private ArrayList<ArrayList<SpectrumBasedDiagnosisResults>> experimentResults;
	
	public FaultLocalizationExperiment(String testSuiteSpreadSheetFile, String policyMutantSpreadsheetFile, 
			String experimentResultFileName, int numberOfRules, int coverageLevel) throws Exception{
		ArrayList<PolicySpreadSheetTestRecord> testSuite = PolicySpreadSheetTestSuite.readTestSuite(testSuiteSpreadSheetFile);
		experimentResults = new ArrayList<ArrayList<SpectrumBasedDiagnosisResults>>();
		policyMutants = PolicySpreadSheetMutantSuite.readMutantSuite(policyMutantSpreadsheetFile);
		// Adding mutant counter
		int num_of_mutants = 1;
		for (PolicyMutant policyMutant: policyMutants ){
			try {
				experimentResults.add(policyMutant.run(testSuite, coverageLevel));
				System.out.println("============================================ " + num_of_mutants);
				System.out.println("Mutant number " + num_of_mutants++ + " Done");
				System.out.println("==============================================================");
			}
			catch (Exception e) {
				e.printStackTrace();
			}		
		}
		if (experimentResults.size()>0) {
			writeExperimentResult(experimentResultFileName, numberOfRules);
		}
	}

	// implement 3 different metrics. 3/30/15
	// Metric 0: Average Ranking
	// Metric 1: % of rules need to inspect to find all the bugs.
	// Metric 2: % detected when inspecting up to 50% of the most suspicious rules
	// Metric 3: # of mutants detected when exam up to top 2 rules.
	
	public void writeExperimentResult(String fileName, int numberOfRules){
		HSSFWorkbook workBook = new HSSFWorkbook();
		workBook.createSheet("mutation testing results");
		Sheet sheet = workBook.getSheetAt(0);
		Row row = sheet.createRow(0);
		writeTitleRow(row, experimentResults.get(0));
		for (int mutantIndex =0; mutantIndex<experimentResults.size(); mutantIndex++){
			row = sheet.createRow(mutantIndex+1);
			writeMutantResultsRow(row, policyMutants.get(mutantIndex).getNumber(), experimentResults.get(mutantIndex)); 
		}
		// 3/30/15 add 3 metrics in writeSummaryRows
		//writeAverageRow(sheet.createRow(experimentResults.size()+2));
		writeSummaryRows(sheet.createRow(experimentResults.size()+2), sheet.createRow(experimentResults.size()+3), 
				sheet.createRow(experimentResults.size()+4), sheet.createRow(experimentResults.size()+5), numberOfRules);
		
		try {
			FileOutputStream out = new FileOutputStream(fileName);
			workBook.write(out);
			out.close();
		}
		catch (IOException ioe){
			ioe.printStackTrace();
		}
	}

	private void writeMutantResultsRow(Row row,String mutantNumber, ArrayList<SpectrumBasedDiagnosisResults> results){
		Cell cell = row.createCell(0);
		cell.setCellValue(mutantNumber);
		for (int i=0; i<results.size(); i++){
			cell = row.createCell(i+1);
			cell.setCellValue(results.get(i).getScore());
		}		
	}

	private void writeSummaryRows(Row row0, Row row1, Row row2, Row row3, int numberOfRules){
		// NOTE
		// experimentResults.get(0).size() : number of formulas.
		// experimentResults.size(): number of mutants.
		int numberOfFormulas = experimentResults.get(0).size();
		int numberOfMutants = experimentResults.size();
		
		double[] totals = new double[numberOfFormulas];
		double[] metric2Totals = new double[numberOfFormulas]; /* #rank/numberOfRules<=50% */
		double[] metric3Totals = new double[numberOfFormulas]; /* #rank<=2 */
		for (int i=0; i<totals.length; i++){
			totals[i]=0.0;
			metric2Totals[i] = 0.0;
			metric3Totals[i] = 0.0;
		}
		for (int mutantIndex=0; mutantIndex<numberOfMutants; mutantIndex++){
			ArrayList<SpectrumBasedDiagnosisResults> results = experimentResults.get(mutantIndex);
			for (int i=0; i<numberOfFormulas; i++){
				totals[i]+= results.get(i).getScore();
				if (results.get(i).getScore()/numberOfRules <= 0.5)
					metric2Totals[i]++;
				if (results.get(i).getScore()<=2)
					metric3Totals[i]++;
			}
		}
		// Average row:
		Cell cell = row0.createCell(0);
		cell.setCellValue("Average");
		for (int i=0; i<numberOfFormulas; i++){
			cell = row0.createCell(i+1);
			if (numberOfMutants>0){
				cell.setCellValue(String.format( "%.3f", totals[i]/numberOfMutants));
			}
		}		
		// Metric 1 row:
		cell = row1.createCell(0);
		cell.setCellValue("Metric1");
		for (int i=0; i<numberOfFormulas; i++) {
			cell = row1.createCell(i+1);
			if (numberOfMutants>0) {
				cell.setCellValue(String.format("%.4f", totals[i]/numberOfMutants/numberOfRules));
			}
		}
		// Metric 2 row:
		cell = row2.createCell(0);
		cell.setCellValue("Metric2");
		for (int i=0; i<numberOfFormulas; i++) {
			cell = row2.createCell(i+1);
			cell.setCellValue(String.format("%.4f", metric2Totals[i]/numberOfMutants));
		}
		// Metric 3 row:
		cell = row3.createCell(0);
		cell.setCellValue("Metric3");
		for (int i=0; i<numberOfFormulas; i++) {
			cell = row3.createCell(i+1);
			cell.setCellValue(String.format("%.0f", metric3Totals[i]));
		}
	}

	
	
	private void writeTitleRow(Row row, ArrayList<SpectrumBasedDiagnosisResults> results){
		Cell cell = row.createCell(0);
		cell.setCellValue("");
		for (int i=0; i<results.size(); i++){
			cell = row.createCell(i+1);
			cell.setCellValue(results.get(i).getMethodName());
		}		
	}
	
	public static void main(String[] args) throws Exception{
		
		// Exclusive - kmarket-blue-policy 
//		new FaultLocalizationExperiment("Experiments//kmarket-blue-policy//test_suites//kmarket-blue-policy_Exclusive//
//										kmarket-blue-policy_Exclusive.xls",
//										"Experiments//kmarket-blue-policy//mutants//kmarket-blue-policy_mutants.xls",
//										"Experiments//kmarket-blue-policy//fault-localization//Exclusive_experiment.xls");
		// Basic - conference3
//		new FaultLocalizationExperiment("Experiments//conference3//test_suites//conference3_Basic//conference3_Basic.xls",
//				"Experiments//conference3//mutants//conference3_mutants.xls",
//				"Experiments//conference3//fault-localization//conference3_Basic_Fault-localiazation.xls");
		

		// General
		String[] policy = { "kmarket-blue-policy",  "kmarket-sliver-policy",  "kmarket-gold-policy", "conference3", "fedora-rule3", 
							"itrust3", "itrust3-5", "itrust3-10", "itrust3-20", "conference3_CRE1"};
		int[] numberOfRules = {4, 5, 3, 15, 12, 
								64, 320, 640, 1280, 15};
		String[] testsuite = {"Basic", "Exclusive", "Pair", "PDpair", "DecisionCoverage", "MCDCCoverage", "RuleLevel"};
		int policyNumber = 9; 
		int testsuiteNumber = 5; // 5 for MCDC Coverage - best mutant score
		int coverageLevel = 0; // 0 - FIREABLE, 1 - REACHABLE, 2 - ADJUSTED WEIGHT REACHABLE

//		/*		
		// Singular experiment
		String testSuiteSpreadSheetFile = "Experiments//" + policy[policyNumber]+ "//test_suites//" 
			+ policy[policyNumber] + "_" + testsuite[testsuiteNumber] + "//" + policy[policyNumber] 
					+ "_" + testsuite[testsuiteNumber] + ".xls";
		String policyMutantSpreadsheetFile = "Experiments//" + policy[policyNumber] + "//mutants//" 
					+ policy[policyNumber] + "_mutants.xls";
		String experimentResultFileName = "Experiments//" + policy[policyNumber] + "//fault-localization//" 
					+ policy[policyNumber] + "_" + testsuite[testsuiteNumber] + "_fault-localiazation" 
					+ "_lev" + coverageLevel + ".xls";
		// Time this.
		final long startTime = System.currentTimeMillis();
		new FaultLocalizationExperiment(testSuiteSpreadSheetFile, policyMutantSpreadsheetFile, 
				experimentResultFileName, numberOfRules[policyNumber], coverageLevel);
		final long endTime = System.currentTimeMillis();
		System.out.println("");
		System.out.println("*******************");
		System.out.println("SBFL results recorded in: " + experimentResultFileName);
		System.out.println("SBFL executing time: " + (endTime - startTime)/1000.00 );
		System.out.println("*******************");
//	*/

		/*
		// Fragment mutation spreadsheet
		for (int partNo=1; partNo<=5; partNo++) {
		
			String testSuiteSpreadSheetFile = "Experiments//" + policy[policyNumber]+ "//test_suites//" 
				+ policy[policyNumber] + "_" + testsuite[testsuiteNumber] + "//" + policy[policyNumber] 
						+ "_" + testsuite[testsuiteNumber] + ".xls";
			String policyMutantSpreadsheetFile = "Experiments//" + policy[policyNumber] + "//mutants//" 
						+ policy[policyNumber] + "_mutants" + "_part" + partNo + ".xls";
			String experimentResultFileName = "Experiments//" + policy[policyNumber] + "//fault-localization//" 
						+ policy[policyNumber] + "_" + testsuite[testsuiteNumber] + "_fault-localiazation" 
						+ "_lev" + coverageLevel + "_part" + partNo + ".xls";
			// Time this.
			final long startTime = System.currentTimeMillis();

			new FaultLocalizationExperiment(testSuiteSpreadSheetFile, policyMutantSpreadsheetFile, 
					experimentResultFileName, numberOfRules[policyNumber], coverageLevel);
			final long endTime = System.currentTimeMillis();

			System.out.println("");
			System.out.println("*******************");
			System.out.println("SBFL results recorded in: " + experimentResultFileName);
			System.out.println("SBFL executing time: " + (endTime - startTime)/1000.00 );
			System.out.println("*******************");
		}
		*/
	}
}
